// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::event_handler::InnerEvent;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::time::SystemTime;

pub(crate) struct InnerQueue<A> {
    handled: u32,
    max_handled: u32,
    queue: VecDeque<InnerEvent<A>>,
}

impl<A> InnerQueue<A> {
    pub(crate) fn new() -> InnerQueue<A> {
        InnerQueue {
            handled: 0,
            max_handled: 5,
            queue: VecDeque::new(),
        }
    }

    fn upper_bound(&self, event: &InnerEvent<A>) -> i32 {
        let mut left = 0_i32;
        let mut right = (self.queue.len() as i32) - 1;
        let mut mid;
        while left <= right {
            mid = left + (right - left) / 2;
            match event.cmp(&self.queue[mid as usize]) {
                Ordering::Less => right = mid - 1,
                Ordering::Greater | Ordering::Equal => left = mid + 1,
            }
        }
        right
    }

    pub(crate) fn set_handled(&mut self, handled: u32) {
        self.handled = handled;
    }

    pub(crate) fn put(&mut self, event: InnerEvent<A>) {
        let upper = self.upper_bound(&event);
        self.queue.insert((upper + 1) as usize, event);
    }

    pub(crate) fn get(&mut self) -> Option<InnerEvent<A>> {
        self.handled += 1;
        self.queue.pop_front()
    }

    pub(crate) fn front(&self) -> Option<&InnerEvent<A>> {
        self.queue.front()
    }

    pub(crate) fn pop_front(&mut self) -> Option<InnerEvent<A>> {
        self.queue.pop_front()
    }

    pub(crate) fn has_expired_event(&self, next: &mut SystemTime) -> bool {
        if self.queue.is_empty() {
            return false;
        }

        if self.handled == self.max_handled {
            return false;
        }

        if let Some(front) = self.front() {
            if *next == SystemTime::UNIX_EPOCH || *next >= front.handle_time() {
                *next = front.handle_time();
                return SystemTime::now() >= front.handle_time();
            }
        }
        false
    }
}
